package com.dev.happy.validation.handle;

import cn.hutool.core.util.StrUtil;
import com.dev.happy.validation.exception.CustomViolationException;
import com.dev.happy.util.SpringBeanUtil;
import com.dev.happy.validation.annotation.CustomValidate;
import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 自定义校验处理
 *
 * @param <T> 校验实体
 * @author caonuoqi
 */
public class CustomValidateHandle<T> {
    public static <T> void validate(T param) {
        //先做其他常规校验，如果常规校验没有通过直接抛出异常结束处理
        Set<ConstraintViolation<T>> errors = Validation.buildDefaultValidatorFactory().getValidator().validate(param);
        if (errors != null && !errors.isEmpty()) {
            throw new ConstraintViolationException("自定义校验", errors);
        } else {
            try {
                List<ValidateBean> validateList = new ArrayList<>();
                //常规校验通过了则进行自定义函数校验
                Class clazz = param.getClass();
                Field[] fields = clazz.getDeclaredFields();
                if (fields != null && fields.length > 0) {
                    for (Field field : fields) {
                        CustomValidate customValidate = field.getAnnotation(CustomValidate.class);
                        if (customValidate != null) {
                            field.setAccessible(true);
                            Object value = field.get(param);
                            ValidateBean validateBean = new ValidateBean(customValidate.order(), value, customValidate.beanName(), customValidate.validateMethod());
                            validateList.add(validateBean);
                        }
                    }
                    if (validateList != null && !validateList.isEmpty()) {
                        Collections.sort(validateList, Comparator.comparing(ValidateBean::getOrder));
                        for (ValidateBean validateBean : validateList) {
                            String result;
                            Object value = validateBean.getTarget();
                            String beanName = validateBean.getBeanName();
                            String validateMethod = validateBean.getValidateMethod();
                            int lastIndex = validateMethod.lastIndexOf(".");
                            String validateClassName = validateMethod.substring(0, lastIndex);
                            String validateMethodName = validateMethod.substring(lastIndex + 1);
                            //如果校验方法的类属于Spring容器管理，则从容器中获取校验的类
                            if (StrUtil.isNotBlank(beanName)) {
                                Object bean = SpringBeanUtil.getBean(beanName);
                                Method validate = bean.getClass().getDeclaredMethod(validateMethodName, value.getClass());
                                result = (String) validate.invoke(bean, value);
                            } else {
                                Class validateClass = Class.forName(validateClassName);
                                Method validate = validateClass.getDeclaredMethod(validateMethodName, value.getClass());
                                Object bean = validateClass.newInstance();
                                result = (String) validate.invoke(bean, value);
                            }
                            if (StringUtils.isNotBlank(result)) {
                                throw new CustomViolationException(result);
                            }
                        }
                    }
                }
            } catch (IllegalAccessException e1) {
                e1.printStackTrace();
            } catch (NoSuchMethodException e2) {
                e2.printStackTrace();
            } catch (InvocationTargetException e3) {
                e3.printStackTrace();
            } catch (ClassNotFoundException e4) {
                throw  new CustomViolationException(String.format("方法：%s未找到",e4.getMessage()));
            } catch (InstantiationException e5) {
                e5.printStackTrace();
            }
        }
    }
}
